if not MySelf then
	MySelf = NULL
end
hook.Add("Think", "GetLocal", function()
	MySelf = LocalPlayer()
	if IsValid(MySelf) then
		gamemode.Call("HookGetLocal", MySelf)
		MySelf.Money = MySelf.Money or 0
		MySelf.MemberLevel = MySelf.MemberLevel or MEMBER_NONE or 0
		--RunConsoleCommand("PostPlayerInitialSpawn")
		hook.Remove("Think", "GetLocal")
	end
end)

local texSpeedometer = Material("hovergear/speedometer.png")
local texNeedle = Material("hovergear/needle.png")
local texHealth = Material("hovergear/health.png")

PowerupDrawModels = {}
PowerupDrawScales = {}
CustomDrawFunctions = {}
Queue = {}

include("shared.lua")
include("sh_colors.lua")

include("cl_options.lua")
include("cl_rotatetext.lua")
include("cl_scoreboard.lua")
include("cl_util.lua")
include("cl_radio.lua")

include("vgui/phelp.lua")
include("vgui/poptions.lua")
include("vgui/padminoptions.lua")
include("vgui/pscoreboard.lua")
include("vgui/dplayerpanel.lua")

function GM:Initialize()
end

function GM:PlayerSpawn(pl)
	pl:SetJumpPower(0)
	
	local col = pl:GetInfo("cl_playercolor")
	pl:SetPlayerColor(Vector(col))
	
	pl.SpectatedPlayerKey = pl.SpectatedPlayerKey or 0
	pl.Racers = pl.Racers or {}
end

local DrawScale = VECSCALE
function GM:PrePlayerDraw(pl)
	pl:SetModelScale(1, 0)
	pl:ShouldDrawLocalPlayer()
end

function GM:HUDPaint()

	local w, h = ScrW(), ScrH()
	local position = "NULL"
	local color = COLOR_GREY
	
	local PlaceTranslation = {
		{"st", COLOR_BLUE},
		{"nd", COLOR_CYAN},
		{"rd", COLOR_GREEN},
		{"th", COLOR_YELLOW},
		{"th", COLOR_RED}
	}
	
	if MySelf and IsValid(MySelf) and not self.HoverGear_FilmMode then

		if not self.EndRaceTime then
			if self.MinimumRacers <= #Queue then
				if self.StartRaceTime then
					draw.DrawText("The race will start in: ".. ToMinutesSeconds(self.StartRaceTime - CurTime()), "NoticeBig", w * 0.5, h*0.05, COLOR_WHITE, TEXT_ALIGN_CENTER)
				end
			else
				draw.DrawText("This game requires at least ".. self.MinimumRacers - #Queue .. " more in the queue list!", "NoticeBig", w * 0.5, h*0.05, COLOR_WHITE, TEXT_ALIGN_CENTER)
			end
		end

		if self.EndRaceTime and self.EndRaceTime > CurTime() then
		
			Racers = team.GetPlayers(TEAM_RACING)
			table.sort(Racers, SortPlayers)
		
			if MySelf:Team() == TEAM_RACING then
				surface.SetDrawColor(color_black_alpha90)
				surface.DrawRect((w/2)-(156/2), 16, 156, 78)
				if self.EndRaceTime - CurTime() >= 60 then
					draw.DrawText(ToMinutesSeconds(self.EndRaceTime - CurTime()), "ScoreboardHead", w * 0.5, 32, COLOR_WHITE, TEXT_ALIGN_CENTER)
				else
					draw.DrawText(ToMinutesMilisecond(self.EndRaceTime - CurTime()), "ScoreboardHead", w * 0.5, 32, COLOR_WHITE, TEXT_ALIGN_CENTER)
				end
				
				surface.SetDrawColor(color_black_alpha90)
				surface.DrawRect(16, 16, 256, 78)
				draw.DrawText("Lap "..MySelf:Frags().." / "..self.LapsToWin-1, "ScoreboardHead", 32, 32, COLOR_WHITE, TEXT_ALIGN_LEFT)

				for i, pl in ipairs(Racers) do
					if PlaceTranslation[i] ~= nil then
						position = PlaceTranslation[i][1]
						color = PlaceTranslation[i][2]
					else
						position = PlaceTranslation[#PlaceTranslation][1]
						color = PlaceTranslation[#PlaceTranslation][2]
					end
					if MySelf == pl then
						surface.SetDrawColor(color_black_alpha90)
						surface.DrawRect(w-256, 16, 240, 78)
						draw.DrawText(i..""..position, "ScoreboardHead", w - 32, 32, color, TEXT_ALIGN_RIGHT)
					end
				end
				
				if IsValid(MySelf:GetHoverGear()) then
					local maxvel = 400
					local speed = MySelf:GetHoverGear():GetVelocity():Length()
					local health = math.Clamp(MySelf:GetHoverGear():GetVehicleHealth(), 0, 250)
					local hcol = HSVToColor(health / 250 * 120, 1,1)
					local currentpower = 0.056818181 * speed * RSCALE
					local currentneedle = math.Clamp((0.056818181 * speed * RSCALE), 0, maxvel)

					surface.SetMaterial(texSpeedometer)
					surface.SetDrawColor(255, 255, 255, 255)
					surface.DrawTexturedRect(0, h-156, 156, 156)

					surface.SetMaterial(texNeedle)
					if currentpower >= maxvel + 15 then
						local mult = math.Clamp(((maxvel + 200 + 15)-currentpower)/200, 0, 1)
						local rand = math.random(maxvel, maxvel * mult)
						surface.SetDrawColor(255, 255*mult, 255*mult, 255)
						surface.DrawTexturedRectRotated(35 - 35 * (rand/maxvel), h - 10 - (23 * (rand/maxvel)), 360, 240, 0 + (90 * (rand/maxvel)))
					else
						surface.SetDrawColor(255, 255, 255, 255)
						surface.DrawTexturedRectRotated(35 - 35 * (currentneedle/maxvel), h - 10 - (23 * (currentneedle/maxvel)), 360, 240, 0 + (90 * (currentneedle/maxvel)))
					end
					draw.DrawText(math.floor(currentpower), "ScoreboardSub", 88, h-58, COLOR_WHITE, TEXT_ALIGN_RIGHT)

					surface.SetMaterial(texHealth)
					surface.SetDrawColor(Color(hcol.r, hcol.g, hcol.b, 220))
					surface.DrawTexturedRect(w-80, h-180, 75, 175)
					
					if health <= 50 then
						local pulse = CurTime() % 1
						if pulse > 0 then
							pulse = pulse ^ 2
							local pulsesize = pulse * 0.5 * 72
							surface.SetDrawColor(hcol.r, hcol.g, hcol.b, 175 - pulse * 175)
							surface.DrawTexturedRect(w-80 - pulsesize, h-180 - pulsesize, 80 + pulsesize * 2, 175 + pulsesize * 2)
						end
					end
					if health <= 0 then
						local pulse = CurTime() % 1.2
						if pulse > 0 then
							pulse = pulse ^ 2
							surface.SetDrawColor(hcol.r, hcol.g, hcol.b, 255 - pulse * 255)
							surface.DrawRect(0, 0, w, 48)
							surface.DrawRect(0, h-48, w, 48)
							surface.DrawRect(0, 0, 48, h)
							surface.DrawRect(w-48, 0, 48, h)
						end
					end
				end
			elseif MySelf:Team() == TEAM_CROWD then
				surface.SetDrawColor(color_black_alpha90)
				surface.DrawRect(w-272, 16, 256, ((h-32)/self.MaximumRacers) * self.MaximumRacers)
				local txtwidth, txtheight = surface.GetTextSize("Racers")
				draw.DrawTextRotated("Racers", "ScoreboardHead", w-230, (h*0.5)-txtheight*2, 90)
				for i, pl in ipairs(Racers) do
					local plname = pl:Name()
					if PlaceTranslation[i] ~= nil then
						position = PlaceTranslation[i][1]
						color = PlaceTranslation[i][2]
					else
						position = PlaceTranslation[#PlaceTranslation][1]
						color = PlaceTranslation[#PlaceTranslation][2]
					end
					draw.DrawText(i..""..position.." "..plname, "ScoreboardSub", w-32, ((h/(self.MaximumRacers+1))*i) - 8, color, TEXT_ALIGN_RIGHT)
				end
			end
			
			if MySelf:Team() == TEAM_CROWD then
				if self.HoverGear_SpectatorMode then
					draw.DrawText("You are in spectator mode. Press LMB or RMB to switch racers.", "NoticeMedium", w*0.5, 32, COLOR_GREEN, TEXT_ALIGN_CENTER)
					if IsValid(self.SpecRacers[self.SpectatedPlayerKey]) then
						draw.DrawText("You are currently spectating "..self.SpecRacers[self.SpectatedPlayerKey]:Name(), "NoticeMedium", w*0.5, h - 96, COLOR_GREEN, TEXT_ALIGN_CENTER)
					end
				end
				draw.DrawText("A race is in progress. Please wait...", "NoticeMedium", w*0.5, h - 44, COLOR_RED, TEXT_ALIGN_CENTER)
			end
		end
		
		if MySelf:Team() == TEAM_CROWD then	
			surface.SetDrawColor(color_black_alpha90)
			surface.DrawRect(16, 16, 258, ((h-32)/self.MaximumRacers) * self.MaximumRacers)
			local txtwidth, txtheight = surface.GetTextSize("Racing Queue List")
			draw.DrawTextRotated("Racing Queue List", "ScoreboardHead", 224, (h*0.5) + (txtwidth + txtheight*2)/2, 270)
			for i = 1, self.MaximumRacers, 1 do
				if IsValid(Queue[i]) then
					plname = Queue[i]:Name()
					draw.DrawText(i..". "..plname, "ScoreboardText", 28, ((h/(self.MaximumRacers+1)) * i) - 8, COLOR_WHITE, TEXT_ALIGN_LEFT)
				else
					draw.DrawText(i..". - EMPTY -", "ScoreboardText", 28, ((h/(self.MaximumRacers+1)) * i) - 8, COLOR_RED, TEXT_ALIGN_LEFT)
				end
			end
		end
	end
end

function GM:PostPlayerDraw(pl)
	if pl:Alive() then
		local offset = Vector(0, 0, 80)
		local ang = pl:EyeAngles()
		local pos = pl:GetPos() + offset + ang:Up() - (ang:Forward()*-2)
	 
		ang:RotateAroundAxis(ang:Forward(), 90)
		ang:RotateAroundAxis(ang:Right(), 90)
	 
		cam.Start3D2D(pos, Angle(0, ang.y, 90), 0.25)
			draw.DrawText(pl:GetName(), "ScoreboardSub", 2, 2, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER)
		cam.End3D2D()
		cam.Start3D2D(pos, Angle(0, ang.y-180, 90), 0.25)
			draw.DrawText(pl:GetName(), "ScoreboardSub", 2, 2, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER)
		cam.End3D2D()
	end
end

function GM:CalcView(pl, origin, angles, fov)
	if not IsValid(pl) or not self.EndRaceTime or not self.HoverGear_SpectatorMode then return end

	self.SpecRacers = {}
	self.SpectatedPlayerKey = self.SpectatedPlayerKey or 0
	
	for k, v in pairs(team.GetPlayers(TEAM_RACING)) do
		if v:Alive() then
			table.insert(self.SpecRacers, v)
		end
	end
	
	if not self.SpecRacers[self.SpectatedPlayerKey] and pl:Team() == TEAM_CROWD then
		self.SpectatedPlayerKey = self.SpectatedPlayerKey < 0 and (#self.SpecRacers or 0) or 0
		return 
	end

	local hovergear = pl:Team() == TEAM_RACING and pl:GetHoverGear() or self.SpecRacers[self.SpectatedPlayerKey]:GetHoverGear()
	local viewmode = pl:Team() == TEAM_RACING and self.HoverGear_VehicleView or self.HoverGear_VehicleView

	if IsValid(hovergear) then
		if viewmode == 0 then --Far View
			--local tr = util.TraceLine({start = origin, endpos = origin - 156 * SCALE * angles:Forward(), mask = MASK_SOLID_BRUSHONLY})
			--tr.HitPos + tr.HitNormal * 8
			origin = hovergear:GetPilotEyePos() + (hovergear:GetAngles():Forward()*-60) + (hovergear:GetAngles():Up()*10) + (hovergear:GetAngles():Right()*3)
			angles = hovergear:GetAngles()
		elseif viewmode == 1 then --Driver's View
			origin = hovergear:GetPilotEyePos() - (hovergear:GetAngles():Forward())
			angles = hovergear:GetAngles()
			angles.Yaw = angles.Yaw - 4
		elseif viewmode == 2 or viewmode == 3 then --Close View
			origin = hovergear:GetPilotEyePos() - (hovergear:GetAngles():Forward()*-1.25) + (hovergear:GetAngles():Up()*1.5) + (hovergear:GetAngles():Right()*2.5)
			angles = hovergear:GetAngles()
			angles.Pitch = angles.Pitch - 5
		end
	end
	return self.BaseClass.CalcView(self, pl, origin, angles, fov)
end

function GM:PlayerBindPress(pl, bind, down)
	if bind == "+duck" and down then --Prevents pseudo-ducking
		if pl:Team() == TEAM_RACING then
			RunConsoleCommand("hovergear_vehicle_view", self.HoverGear_VehicleView + 1)
			return true
		else
			RunConsoleCommand("hovergear_spec_mode", self.HoverGear_SpectatorMode == false and 1 or 0)
			return true
		end
	end
	if bind == "+attack" and down and self.HoverGear_SpectatorMode and pl:Team() == TEAM_CROWD then
		self.SpectatedPlayerKey = (self.SpectatedPlayerKey or 0) + 1
		return true
	elseif bind == "+attack2" and down and self.HoverGear_SpectatorMode and pl:Team() == TEAM_CROWD then
		self.SpectatedPlayerKey = (self.SpectatedPlayerKey or 0) - 1
		return true
	end
	if bind == "+jump" and down then --Prevents pseudo-jumping
		if pl:Team() == TEAM_CROWD and self.HoverGear_SpectatorMode then
			RunConsoleCommand("hovergear_vehicle_view", self.HoverGear_VehicleView + 1)
			return true
		end
	end
	if bind == "+reload" and down then
		pl:ConCommand("kill")
		return true
	end
end

function GM:RenderScreenspaceEffects()
end

function GM:PostProcessPermitted(str)
	return false
end

function GM:HUDShouldDraw(name)
	return name ~= "CHudHealth" and name ~= "CHudBattery"
end

function GM:HookGetLocal(pl)
end

function GM:QueueUpdated()
end

function GM:GameStateUpdated()
end

function WorldToScreen(vWorldPos, vPos, vScale, aRot)
    local vWorldPos = vWorldPos - vPos;
    vWorldPos:Rotate(Angle(0,-aRot.y,0));
    vWorldPos:Rotate(Angle(-aRot.p,0,0));
    vWorldPos:Rotate(Angle(0,0,-aRot.r));
    return vWorldPos.x/vScale,(-vWorldPos.y)/vScale;
end

function ToMinutesSeconds(TimeInSeconds)
	local iMinutes = math.floor(TimeInSeconds / 60.0)
	return string.format("%0d:%02d", iMinutes, math.floor(TimeInSeconds - iMinutes*60))
end

function ToMinutesMilisecond(TimeInSeconds)
	local iSeconds = string.ToMinutesSecondsMilliseconds(TimeInSeconds+0.1)
	local numbers = string.Explode(":", iSeconds)
	return tostring(numbers[#numbers-1].."."..string.sub(numbers[#numbers], 1, 2))
end

usermessage.Hook("PlayerSpawn", function(um)
	local pl = um:ReadEntity()
	if IsValid(pl) then
		gamemode.Call("PlayerSpawn", pl)
	end
end)

usermessage.Hook("updateracingqueue", function(um)
	Queue = {}

	for i, id in ipairs(string.Explode(",", um:ReadString())) do
		if IsValid(Entity(id)) then
			Queue[i] = Entity(id)
		end
	end

	gamemode.Call("QueueUpdated")
end)

usermessage.Hook("updgmstate", function(um)
	GAMEMODE.Racing = um:ReadBool()
	local startracetime = um:ReadFloat()
	if startracetime == 0 then
		GAMEMODE.StartRaceTime = nil
	else
		GAMEMODE.StartRaceTime = startracetime
	end
	local endracetime = um:ReadFloat()
	if endracetime == 0 then
		GAMEMODE.EndRaceTime = nil
	else
		GAMEMODE.EndRaceTime = endracetime
	end

	gamemode.Call("GameStateUpdated")
end)